﻿using System;
using System.Globalization;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Xml;
using System.Reflection;
using Services;
using Utilities.Menu.UIElements;
using BowMaster.Resources;
using Utilities;

namespace BowMaster.SceneElements
{
    public class HitBox
    {
        public Rectangle box;
        public float value;
    }
    public abstract class ATarget
    {
        protected Texture2D texture;
        public Rectangle drawRect;
        //Rectangle target;
        public ArrayList<HitBox> hitBoxes;
        Color color;
        public ATarget(Texture2D texture, Color color, Rectangle drawRect, ArrayList<HitBox> hitBoxes)
        {
            this.texture = texture;
            this.drawRect = drawRect;
            //this.target = target;
            this.hitBoxes = hitBoxes;
            this.color = color;
            //UpdateRectangles();
        }
        /// <summary>
        /// Contructor for baloon
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="color"></param>
        /// <param name="drawRect"></param>
        public ATarget(Texture2D texture, Color color, Rectangle drawRect)
            : this(texture, color, drawRect, new ArrayList<HitBox>())
        { }
        /// <summary>
        /// Constructor for target with hitboxes
        /// </summary>
        /// <param name="texture"></param>
        /// <param name="drawRect"></param>
        /// <param name="target"></param>
        public ATarget(Texture2D texture, Rectangle drawRect)
            : this(texture, Color.White, drawRect, new ArrayList<HitBox>())
        { }
        ///// <summary>
        ///// Constructor for target with apple on the head
        ///// </summary>
        ///// <param name="texture"></param>
        ///// <param name="drawRect"></param>
        ///// <param name="target"></param>
        ///// <param name="hitBoxes"></param>
        //public ATarget(Texture2D texture, Rectangle drawRect, ArrayList<HitBox> hitBoxes)
        //    : this(texture, Color.White, drawRect, hitBoxes)
        //{ }

        public virtual void Draw(SpriteBatch spriteBatch, Matrix view, Matrix projection)
        {
            spriteBatch.DrawTexture(texture, drawRect, color, view, projection);
        }
        public virtual void Draw(SpriteBatch spriteBatch, Matrix view, Matrix projection, float distance)
        {
            spriteBatch.DrawTexture(texture, drawRect, distance, color, view, projection);
        }
        public virtual void DrawHitBoxes(SpriteBatch spriteBatch, Matrix view, Matrix projection, Texture2D text)
        {
            for(int i =0;i<hitBoxes.Count;i++)
                spriteBatch.DrawTexture(text, hitBoxes[i].box, Color.Red/*Color.Lerp(Color.Blue,Color.Red,(float)i/(float)hitBoxes.Count)*/, view, projection);
        }
        protected void UpdateHitBoxes(int deltax, int deltay)
        {
            //this.target.X += drawRect.X;
            //this.target.Y += drawRect.Y;

            for (int i = 0; i < hitBoxes.Count; i++)
            {
                hitBoxes[i].box.X += deltax;
                hitBoxes[i].box.Y += deltay;
            }
        }
    }

    public class BaloonTarget : ATarget
    {
        static int width = 80;
        static int height = 90;
        Vector2 position;
        public Vector2 velocity;
        Texture2D[] textures;
        public bool popped = false;
        public bool remove = false;
        float time_since_popped;

        public BaloonTarget(Texture2D [] textures, Color color, Vector2 position, Vector2 velocity)
            : base(textures[0], color, new Rectangle((int)position.X - width / 2, (int)position.Y - height / 2, width, height))
        {
            this.position = position;
            this.velocity = velocity;
            this.textures = textures;
            hitBoxes.Add(new HitBox()
            {
                value = 0,
                box = new Rectangle(drawRect.X + 57 * width / texture.Width, drawRect.Y + 62 * height / texture.Height, 104 * width / texture.Width, 114 * height / texture.Height)
            });
        }
        public void Update(float dt)
        {
            if(popped)
            {
                var index = (int)(time_since_popped / 0.02f);
                if (index >= textures.Length)
                {
                    remove = true;
                    return;
                }
                texture = textures[index];                
                time_since_popped += dt;
            }
            position += velocity * dt;

            
            drawRect.X = (int)position.X - width / 2;
            drawRect.Y = (int)position.Y - height / 2;
            hitBoxes[0].box.X = drawRect.X + 57 * width / texture.Width;
            hitBoxes[0].box.Y = drawRect.Y + 62 * height / texture.Height;
            //UpdateHitBoxes(deltax, deltay);
        }

    }

    public class StaticTarget : ATarget
    {
        static int width = 90;
        static int height = 140;
        //Texture2D texture;

        public StaticTarget(Texture2D texture, int x, int level_y)
            : base(texture, new Rectangle(x, level_y - 100 - width / 2, width, height))
        {
            //this.texture = texture;
            level_y -= 145;
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 120, 216, 17, 91),
                value = 10
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 120, 175, 26, 171),
                value = 6
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 120, 118, 32, 285),
                value = 4
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 120, 69, 99, 383),
                value = 2
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 120, 6, 99, 483),
                value = 1
            });
        }

        private Rectangle ScaleRect(int offset_x, int offset_y, int x, int y, int w, int h)
        {
            return new Rectangle(offset_x +5+ x * width / texture.Width, offset_y + y * height / texture.Height, 20, h * height / texture.Height);
        }
        
    }

    public class AppleTarget : ATarget
    {
        static int width = 35;
        static int height = 137;
        //Texture2D texture;
        BoundingSphere apple;
        public float life;
        public float max_life;
        Rectangle lifeRect;
        Texture2D lifeText;
        public bool appleHitted;
        Rectangle a;

        public AppleTarget(Texture2D texture, Texture2D lifeTexture, int x, int level_y, float life)
            : base(texture, new Rectangle(x, level_y - height / 2 - 70, width, height))
        {
            //this.texture = texture;
            this.life = this.max_life = life;
            this.lifeText = lifeTexture;
            appleHitted = false;
            lifeRect = new Rectangle(drawRect.X, drawRect.Y - 10, drawRect.Width, 4);
            level_y -= height * height / texture.Height;
            a= ScaleRect(x, level_y, 17, 2, 9, 13);

            apple = new BoundingSphere(new Vector3(a.Center.X, a.Center.Y, 0), a.Height / 2);
            //apple = new HitBox()
            //{
            //    box = ScaleRect(x, level_y, 17, 2, 9, 13),
            //    value=1
            //};
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 8, 16, 23, 23),
                value = 0.5f
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 14, 39, 11, 69),
                value = 0.2f
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 24, 46, 8, 43),
                value = 0.2f
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 5, 52, 8, 36),
                value = 0.2f
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 11, 108, 14, 27),
                value = 0.1f
            });
            hitBoxes.Add(new HitBox()
            {
                //box = new Rectangle(x + 141 * width / texture.Width, y + 219 * height / texture.Height, 36 * width / texture.Width, 87 * height / texture.Height),
                box = ScaleRect(x, level_y, 5, 130, 6, 5),
                value = 0.1f
            });
        }

        private Rectangle ScaleRect(int offset_x, int offset_y, int x, int y, int w, int h)
        {
            return new Rectangle(offset_x + x * width / texture.Width, offset_y + y * height / texture.Height,
                w*width/texture.Width, h * height / texture.Height);
        }
        public bool Hitted(Arrow a)
        {

            if (StaticUtilities.RectContainsVect(apple, a))
            {
                appleHitted = true;
                return true;
            }
            bool hit = false;
            for (int i = 0; i < hitBoxes.Count; i++)
            {
                var h = hitBoxes[i];
                if (StaticUtilities.RectContainsVect(h.box, a.point))
                {
                    hit = true;
                    life -= max_life * h.value;
                    lifeRect.Width = (int)(drawRect.Width * life / max_life);
                    break;
                }
            }

            return hit;
        }
        public override void Draw(SpriteBatch spriteBatch, Matrix view, Matrix projection)
        {
            base.Draw(spriteBatch, view, projection, -1);
            spriteBatch.DrawTexture(lifeText, lifeRect, -1, Color.Red, view, projection);
            
        }
        public override void DrawHitBoxes(SpriteBatch spriteBatch, Matrix view, Matrix projection, Texture2D text)
        {
            base.DrawHitBoxes(spriteBatch, view, projection, text);
            spriteBatch.DrawTexture(text, a, 0.2f,Color.Blue, view, projection);
        }
    }







    public class StaticTarget3D : ATarget
    {
        static int height = 50;
        static int circonference = 70;
        //Texture2D texture;
        Plane box;
        BoundingSphere sphere;
        Matrix transform, transform_i;

        public StaticTarget3D(Texture2D texture, int x, int level_y)
            : base(texture, new Rectangle(x, level_y - 100 - height / 2, circonference, circonference))
        {
            //this.texture = texture;
            transform =
                Matrix.CreateTranslation(new Vector3(-0.5f,0, 0)) *
                Matrix.CreateRotationX(-0.1f) *
                Matrix.CreateRotationY(0.8f) *
                //Matrix.CreateTranslation(new Vector3(0.5f,0, 0)) *
                Matrix.CreateScale(new Vector3(circonference, circonference, 1)) *
                Matrix.CreateTranslation(new Vector3(x,level_y-circonference-height, 0));

            var corner1 = Vector3.Transform(new Vector3(0,100,0), transform);
            var corner2 = Vector3.Transform(new Vector3(100, 0, 0), transform); 
            var corner3 = Vector3.Transform(new Vector3(100, 100, 0), transform);
            box = new Plane(corner1, corner2, corner3);
            sphere = new BoundingSphere(Vector3.Transform(new Vector3(0.5f, 0.5f, 0), transform), circonference/2);           
        }

        //private Rectangle ScaleRect(int offset_x, int offset_y, int x, int y, int w, int h)
        //{
        //    return new Rectangle(offset_x + x * width / texture.Width, offset_y + y * height / texture.Height, 30, h * height / texture.Height);
        //}


        override public void Draw(SpriteBatch spriteBatch, Matrix view, Matrix projection)
        {
            spriteBatch.DrawTexture(texture, Color.White, transform, view, projection);

            //spriteBatch.DrawTexture(texture, Color.Red * 0.5f,
            //    Matrix.CreateTranslation(new Vector3(-0.5f, -0.5f, 0)) *
            //    Matrix.CreateScale(sphere.Radius * 2) * Matrix.CreateTranslation(sphere.Center), view, projection);
        }


        Vector3 lasthitpoint3d;
        public bool isHitted(Arrow arrow)
        {
            var ray = new Ray(new Vector3(arrow.point, 0), -new Vector3(arrow.point-arrow.position, 0));

            var hit_dist = ray.Intersects(box);
            if (hit_dist.HasValue)
            {
                lasthitpoint3d = ray.Position + Vector3.Normalize(ray.Direction) * hit_dist.Value;
                var dist = Vector3.Distance(lasthitpoint3d, sphere.Center);
                
            }

            return hit_dist.HasValue && sphere.Contains(lasthitpoint3d) != ContainmentType.Disjoint;
        }


        public Vector2 getLastHitPoint()
        {
            var hit_point = Vector3.Transform(lasthitpoint3d, Matrix.Invert(transform));
            Console.WriteLine(hit_point);
            return new Vector2(hit_point.X, hit_point.Y); 
        }

    }

}
